﻿namespace SugarTank.Mobile.Managers
{
    using System;
    using System.IO;
    using System.Windows.Threading;
    using CommonTypes.Phone;
    using Contracts;
    using Helpers;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Audio;

    public class MediaManager : IMediaManager
    {
        /// <summary>
        /// Occurs when [microphone recording started].
        /// </summary>
        public event EventHandler<EventArgs> MicrophoneRecordingStarted;

        /// <summary>
        /// Occurs when [microphone recording stopped].
        /// </summary>
        public event EventHandler<EventArgs<MicrophoneResult>> MicrophoneRecordingStopped;

        /// <summary>
        /// The microphone (from the XNA framework).
        /// </summary>
        private readonly Microphone microphone;

        /// <summary>
        /// The dispatcher timer for XNA.
        /// </summary>
        private readonly DispatcherTimer dispatcherTimer;

        /// <summary>
        /// The stream for recording audio.
        /// </summary>
        private readonly MemoryStream microphoneRecording  = new MemoryStream();

        /// <summary>
        /// The microphone recording buffer.
        /// </summary>
        private byte[] microphoneRecordingBuffer;

        /// <summary>
        /// Initializes a new instance of the <see cref="MediaManager"/> class.
        /// </summary>
        public MediaManager()
        {
            this.dispatcherTimer = new DispatcherTimer();
            dispatcherTimer.Interval = TimeSpan.FromMilliseconds(33);
            dispatcherTimer.Tick += delegate { FrameworkDispatcher.Update(); };

            this.microphone = Microphone.Default;
            this.microphone.BufferReady += this.OnMicrophoneBufferReady;
        }

        #region IMediaManager Members

        /// <summary>
        /// Starts the microphone recording.
        /// </summary>
        public void StartMicrophoneRecording()
        {
            this.microphoneRecording.SetLength(0);

            dispatcherTimer.Start();

            this.microphone.BufferDuration = TimeSpan.FromMilliseconds(500);
            this.microphoneRecordingBuffer = new byte[this.microphone.GetSampleSizeInBytes(this.microphone.BufferDuration)];
            this.microphone.Start();

            this.MicrophoneRecordingStarted.FireEvent(this, () => EventArgs.Empty);
        }

        /// <summary>
        /// Stops the microphone recording.
        /// </summary>
        public void StopMicrophoneRecording()
        {
            if (this.microphone.State == MicrophoneState.Started)
            {
                this.microphone.Stop();

                this.MicrophoneRecordingStopped.FireEvent(this, () => new EventArgs<MicrophoneResult>(
                    new MicrophoneResult(
                    this.microphoneRecording.ToArray(), 
                    this.microphone.SampleRate, 
                    AudioChannels.Mono)));

                this.dispatcherTimer.Stop();
            }
        }

        #endregion

        /// <summary>
        /// Called when [microphone buffer ready].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void OnMicrophoneBufferReady(object sender, EventArgs e)
        {
            this.microphone.GetData(this.microphoneRecordingBuffer);
            this.microphoneRecording.Write(this.microphoneRecordingBuffer, 0, this.microphoneRecordingBuffer.Length);
        }
    }
}